package com.sc.nft.controller;

import com.sc.nft.annotation.UserLogin;
import com.sc.nft.entity.vo.mall.*;
import com.sc.nft.entity.vo.mall.req.WxMiniOrderCreateByCartReq;
import com.sc.nft.entity.vo.mall.req.WxMiniOrderCreateReq;
import com.sc.nft.entity.vo.mall.req.WxMiniOrderPreviewByCartReq;
import com.sc.nft.entity.vo.mall.req.WxMiniOrderPreviewReq;
import com.sc.nft.enums.RedisKeyEnum;
import com.sc.nft.exception.GlobalException;
import com.sc.nft.exception.GlobalRunTimeException;
import com.sc.nft.feign.WxMallCartClient;
import com.sc.nft.pool.UserPool;
import com.sc.nft.req.mallCart.CartListReq;
import com.sc.nft.service.WxMiniMallOrderService;
import com.sc.nft.sup.ErrorCode;
import com.sc.nft.sup.Result;
import com.sc.nft.vo.mallcart.MallCartListVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author liGen
 * @version 1.0
 * @date 2023/12/6 3:50 下午
 */
@Slf4j
@RequiredArgsConstructor
@RestController
@RequestMapping("/ipMall/wxMiniMall/order")
@Api(tags = "小程序商城订单")
public class WxMiniMallOrderController {

    private final WxMiniMallOrderService wxMiniMallOrderService;
    private final WxMallCartClient wxMallCartClient;
    private final Redisson redisson;


    @ApiOperation(value = "小程序订单预览", notes = "小程序订单预览", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/preview", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public Result<MiniMallOrderPreviewVO> miniMallOrderPreview(@Valid @RequestBody WxMiniOrderPreviewReq request) throws GlobalException {
        MiniMallOrderPreviewVO miniMallOrderPreviewVO = null;
        // 商品锁
        RLock lock = redisson.getLock(RedisKeyEnum.IP_PRODUCT_STOCK_LOCK.getKey() + request.getActivityId());
        // 小程序用户锁
        RLock userLock = redisson.getLock(RedisKeyEnum.MALL_SMALL_PROGRAM_ORDER_USER_LOCK.getKey() + UserPool.getWxMiniUserId());

        try {
            boolean res = lock.tryLock(3, 10, TimeUnit.SECONDS);
            if (res) {

                boolean userLockRes = userLock.tryLock(3, 10, TimeUnit.SECONDS);

                if (!userLockRes) {
                    return Result.fail("当前人数过多，请稍后再试!");
                }
                miniMallOrderPreviewVO = wxMiniMallOrderService.miniMallOrderPreview(request, UserPool.getWxMiniUser());
            } else {
                return Result.fail("当前人数过多，请稍后再试!");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
            throw new GlobalRunTimeException("系统超时");
        } finally {
            lock.unlock();
            userLock.unlock();
        }
        return Result.success(miniMallOrderPreviewVO);
    }

    @ApiOperation(value = "小程序订单预览(通过购物车)", notes = "小程序订单预览(通过购物车)", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/previewByCart", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public Result<MiniMallOrderPreviewVO> miniMallOrderPreviewByCart(@Valid @RequestBody WxMiniOrderPreviewByCartReq request) throws GlobalException {
        MiniMallOrderPreviewVO miniMallOrderPreviewVO = null;
        // 小程序用户锁
        RLock userLock = redisson.getLock(RedisKeyEnum.MALL_SMALL_PROGRAM_ORDER_USER_LOCK.getKey() + UserPool.getWxMiniUserId());

        try {
            boolean res = userLock.tryLock(3, 10, TimeUnit.SECONDS);
            if (res) {
                miniMallOrderPreviewVO = wxMiniMallOrderService.miniMallOrderPreviewByCart(request, UserPool.getWxMiniUser());
            } else {
                return Result.fail("当前人数过多，请稍后再试!");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
            throw new GlobalRunTimeException("系统超时");
        } finally {
            userLock.unlock();
        }
        return Result.success(miniMallOrderPreviewVO);
    }

    @ApiOperation(value = "创建商城小程序订单", notes = "创建商城小程序订单", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/create", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public Result<MiniMallOrderConfirmVO> miniMallOrderCreate(@Valid @RequestBody WxMiniOrderCreateReq request) throws GlobalException {
        MiniMallOrderConfirmVO miniMallOrderConfirmVO = null;
        // 商品锁
        RLock lock = redisson.getLock(RedisKeyEnum.IP_PRODUCT_STOCK_LOCK.getKey() + request.getActivityId());
        // 小程序用户锁
        RLock userLock = redisson.getLock(RedisKeyEnum.MALL_SMALL_PROGRAM_ORDER_USER_LOCK.getKey() + UserPool.getWxMiniUserId());

        try {
            boolean res = lock.tryLock(3, 10, TimeUnit.SECONDS);
            if (res) {

                boolean userLockRes = userLock.tryLock(3, 10, TimeUnit.SECONDS);

                if (!userLockRes) {
                    return Result.fail("当前人数过多，请稍后再试!");
                }
                miniMallOrderConfirmVO = wxMiniMallOrderService.miniMallOrderCreate(request, UserPool.getWxMiniUser());
            } else {
                return Result.fail("当前人数过多，请稍后再试!");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
            throw new GlobalRunTimeException("系统超时");
        } finally {
            lock.unlock();
            userLock.unlock();
        }
        return Result.success(miniMallOrderConfirmVO);
    }

    @ApiOperation(value = "创建商城小程序订单", notes = "创建商城小程序订单", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/createByCart", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public Result<MiniMallOrderConfirmVO> miniMallOrderCreateByCart(@Valid @RequestBody WxMiniOrderCreateByCartReq request) throws GlobalException {
        MiniMallOrderConfirmVO miniMallOrderConfirmVO = null;
        // 小程序用户锁
        RLock userLock = redisson.getLock(RedisKeyEnum.MALL_SMALL_PROGRAM_ORDER_USER_LOCK.getKey() + UserPool.getWxMiniUserId());
        List<RLock> locks = new ArrayList();
        try {
            boolean res = userLock.tryLock(3, 10, TimeUnit.SECONDS);
            if (res) {
                List<Long> missingLockActivityIdList = new ArrayList<>();
                // 获取需要创建订单的购物车列表
                Result<List<MallCartListVO>> listResult = wxMallCartClient.cartList(CartListReq.build(request.getCartIds(), UserPool.getWxMiniUser().getId()));
                List<MallCartListVO> mallCartListVOList = listResult.getData();
                List<Long> activityIds = mallCartListVOList.stream().map(mallCartListVO -> mallCartListVO.getActivityId()).collect(Collectors.toList());
                for (Long activityId : activityIds) {
                    // 商品锁
                    RLock lock = redisson.getLock(RedisKeyEnum.IP_PRODUCT_STOCK_LOCK.getKey() + activityId);
                    boolean canCreate = lock.tryLock(10, TimeUnit.SECONDS);
                    if (!canCreate) {
                        missingLockActivityIdList.add(activityId);
                    } else {
                        locks.add(lock);
                    }
                }
                if (missingLockActivityIdList.size() > 0) {
                    // 只要有一个锁获取失败 就无法创建订单
                    throw new GlobalException(ErrorCode.COUNT_NOT_ENOUGH);
                }
                miniMallOrderConfirmVO = wxMiniMallOrderService.miniMallOrderCreateByCart(request, UserPool.getWxMiniUser(), mallCartListVOList);
            } else {
                return Result.fail("当前人数过多，请稍后再试!");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
            throw new GlobalRunTimeException("系统超时");
        } finally {
            userLock.unlock();
            // 批量释放锁
            locks.forEach(lock -> {
                lock.unlock();
                log.info("购物车创建订单释放锁:{}", lock);

            });
        }
        return Result.success(miniMallOrderConfirmVO);
    }
}